Session Managerを使ってEC2の先にあるRDSに接続してみた
こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。
最近、AWS System ManagerのSession Managerを利用するとポートフォワーディングができるということをはじめて知りました。
ただ、このままだと接続先のEC2上のポートをローカルにフォワーディングできるのですが、更にEC2を踏み台にして、その先のRDSに接続するというようなことは出来ません。
この場合はSession Manager経由でSSHをすれば良いのですが、この場合にはどうしてもキーが必要になります。
個人的にこのキーの管理が煩雑だったため、どうにかできないか試してみました。
2022/05/30(月) 追記
このエントリでやりたかったことは、AWS System Managerで正式に対応されました!(irbbbさんの下記エントリ参照)
ですので、このエントリは過去の情報として参考程度にご参照いただければと思います。
前提
今回の環境は以下のような環境です。
- 接続先のEC2はAmazon Linux 2
- EC2はSession Managerで接続できるように設定済み
- 接続元のローカルPCも接続先EC2にSession Manager経由で接続できるように設定済み
- EC2からしかアクセスできないRDSがあって、ここにローカルPCからアクセスしたい
対応方針を検討する
EC2上のポートをローカルにフォワーディングするのは簡単にできるので、あとはEC2とRDS間をどうするかです。
ここは、今回はsocat
を利用したいと思います。標準ではAmazon Linux 2にインストールされていないのでインストールする必要が出てきてしまうのですが、目をつむります。
socatコマンドを利用したTCPリレーについては、以前に書いた通りなのでこれをそのままSSMのRumCommandで実行し、その後にEC2上のポートをローカルにフォワーディングする方向でやってみます。
EC2 - RDS間のポートリレーをさせる
今回はすべてローカルPC上から操作を完結させたいので、SSMドキュメントを作成して実行させるようにします。
まずは以下のようなドキュメントを用意します。
--- schemaVersion: "2.2" description: Port Forwarding parameters: localPort: type: String default: "5432" description: "フォワーディング元のポート番号を指定" targetHost: type: String default: "" description: "フォワーディング対象ホストを指定" targetPort: type: String default: "5432" description: "フォワーディング先のポート番号を指定" mainSteps: - action: aws:runShellScript name: install inputs: runCommand: - yum install socat -y - action: aws:runShellScript name: run inputs: runCommand: - socat tcp4-listen:{{ localPort }},reuseaddr,fork TCP:{{ targetHost }}:{{ targetPort }}
ドキュメントが準備できたらCLIから登録します。以下のようなシェルを作成して登録してみました。念の為に、事前に同名ドキュメントを削除するコマンドも入れています。
#!/bin/bash DOCUMENT_NAME=port-relay aws ssm delete-document \ --name ${DOCUMENT_NAME} aws ssm create-document \ --content file://./command-document.yml \ --name ${DOCUMENT_NAME} \ --document-type "Command" \ --document-format "YAML"
ドキュメントが登録できたら、実際に実行します。こちらも以下のようなシェルを作成して実行してみました。
#!/bin/bash INSTANCE_ID=i-xxxxxxxxxxxxxxxxx DOCUMENT_NAME=port-relay TARGET_HOST="foobar.ap-northeast-1.rds.amazonaws.com" aws ssm send-command \ --instance-ids ${INSTANCE_ID} \ --document-name ${DOCUMENT_NAME} \ --parameters targetHost=${TARGET_HOST}
これで、EC2でsocatコマンドが実行されている状態になります。
ローカルPCにポートフォワーディング
あとはローカルPCにポートフォワーディングするだけです。以下のシェルを実行してポートフォワーディングします。
#!/bin/bash INSTANCE_ID=i-xxxxxxxxxxxxxxxxx aws ssm start-session \ --target ${INSTANCE_ID} \ --document-name AWS-StartPortForwardingSession \ --parameters portNumber=5432,localPortNumber=5432
これで、localhost:5432
にアクセスすれば、EC2上の先にあるRDSにアクセスできるようになりました!
課題
一見よさそうですが、ちょっと問題があります。
下記の記事にもある通り、RunCommandで実行されているコマンドには「実行タイムアウト」が7200
秒で設定されています。このため、2時間経過するとsocatのプロセスが死んでしまうという問題があります
socatコマンドの実行をシェルスクリプト化したり、RunCommandで実行するコマンドをnohup xxx &
のようにしたりもしてみたのですが、RunCommandで実行されるコマンドには効果がなく、現状では解決策が見つかりませんでした。
良い方法が見つかったら後で追記したいと思います。
まとめ
以上、Session Managerを使ってポートフォワーディングをしてみました。Session Managerを利用すると、これまでのようにEC2インスタンスにパブリックIP経由でSSH接続せずとも色々と作業ができるのを知ったので、これから活用していきたいと思います。
どなたかのお役に立てば幸いです。それでは!